from zhipuai import ZhipuAI
import pickle
import pandas as pd
import re

class CareerAdvisor:
    def __init__(self, api_key, apriori_path='apriori.bin', dataset_path='processed_dataset.csv'):
        """初始化职业顾问系统"""
        self.client = ZhipuAI(api_key=api_key)
        self.frequent_itemsets, self.rules = self._load_apriori(apriori_path)
        self.data = self._load_dataset(dataset_path)
    
    def _load_apriori(self, file_path):
        """加载关联规则数据"""
        with open(file_path, 'rb') as f:
            return pickle.load(f)
    
    def _load_dataset(self, file_path):
        """加载处理后的数据集"""
        data = pd.read_csv(file_path)
        data['skill_list'] = data['skill_list'].apply(lambda x: x.split(', ') if isinstance(x, str) else [])
        return data
    
    def get_associated_skills(self, target_skill, min_support=0.05):
        """获取与目标技能相关联的其他技能"""
        target_skill = target_skill.lower()
        relevant_rules = self.rules[self.rules['antecedents'].apply(lambda x: target_skill in x)]
        relevant_rules = relevant_rules[relevant_rules['support'] >= min_support]
        result = set()
        for _, row in relevant_rules.iterrows():
            result.update(row['consequents'])
        return list(result)
    
    def get_skills_by_position(self, position_name):
        """获取特定岗位需要的技能，返回出现频率最高的 3 - 5 个技术及其百分占比"""
        position_data = self.data[self.data['positionName'].str.contains(position_name, case=False, na=False)]
        if position_data.empty:
            return []
        
        total_skills_count = 0
        skill_count = {}
        for skills in position_data['skill_list']:
            for skill in skills:
                if skill in skill_count:
                    skill_count[skill] += 1
                else:
                    skill_count[skill] = 1
            total_skills_count += len(skills)
        
        # 计算百分占比
        skill_percentage = {skill: (count / total_skills_count) * 100 for skill, count in skill_count.items()}
        
        # 按频率排序
        sorted_skills = sorted(skill_percentage.items(), key=lambda x: x[1], reverse=True)
        
        # 选取前 3 - 5 个技术
        top_skills = [(skill[0], f"{skill[1]:.2f}%") for skill in sorted_skills[:5]]
        if len(top_skills) < 3:
            return top_skills
        return top_skills[:3] if len(top_skills) >= 3 else top_skills

    def get_positions_by_skills(self, skill_names):
        """获取需要多个技能的岗位（同时满足所有技能），返回出现频率最高的 3 - 5 个岗位及其百分占比"""
        skill_list = [s.strip().lower() for s in re.split(r'和|与|及|,|、', skill_names)]
        position_data = self.data[self.data['skill_list'].apply(
            lambda x: all(skill in [s.lower() for s in x] for skill in skill_list)
        )]
        if position_data.empty:
            return []
        
        total_positions_count = len(position_data)
        position_count = {}
        positions = position_data['positionName'].tolist()
        for position in positions:
            if position in position_count:
                position_count[position] += 1
            else:
                position_count[position] = 1
        
        # 计算百分占比
        position_percentage = {position: (count / total_positions_count) * 100 for position, count in position_count.items()}
        
        # 按频率排序
        sorted_positions = sorted(position_percentage.items(), key=lambda x: x[1], reverse=True)
        
        # 选取前 3 - 5 个岗位
        top_positions = [(position[0], f"{position[1]:.2f}%") for position in sorted_positions[:5]]
        if len(top_positions) < 3:
            return top_positions
        return top_positions[:3] if len(top_positions) >= 3 else top_positions
    
    def get_associated_skills_multiple(self, skill_names, min_support=0.05):
        """获取与多个技能相关联的其他技能"""
        skill_list = [s.strip().lower() for s in re.split(r'和|与|及|,|、', skill_names)]
        combined_skills = set()
        
        for skill in skill_list:
            associated = self.get_associated_skills(skill, min_support)
            combined_skills.update(associated)
        
        # 移除查询的技能本身
        combined_skills.difference_update(set(skill_list))
        return list(combined_skills)
    
    def _query_single(self, user_question, query_type, query_param):
        """处理单技能查询的辅助方法"""
        result_str = ""
        if query_type == 'skill_association':
            result = self.get_associated_skills(query_param)
            if not result:
                result_str = f"没有找到与'{query_param}'相关的技术推荐。"
            else:
                result_str = f"根据关联规则分析，与'{query_param}'相关的技术有: {', '.join(result)}"
        
        elif query_type == 'position_skills':
            result = self.get_skills_by_position(query_param)
            if not result:
                result_str = f"没有找到'{query_param}'岗位的技术要求信息。"
            else:
                skill_info = [f"{skill} ({percentage})" for skill, percentage in result]
                result_str = f"从事{query_param}岗位通常需要掌握以下技术（百分占比）: {', '.join(skill_info)}"
        
        elif query_type == 'skill_positions':
            result = self.get_positions_by_skill(query_param)
            if not result:
                result_str = f"没有找到需要'{query_param}'技能的岗位。"
            else:
                result_str = f"掌握{query_param}技能可以应聘以下岗位: {', '.join(result)}"
        
        else:
            result_str = "无效的查询类型。"
        
        print(f"查询结果: {result_str}")  # 打印查询结果

        # 使用LLM生成自然语言回答
        prompt = f"""
        用户问题: {user_question}
        
        查询结果: {result_str}
        
        你是一个帮助学生规划职业道路的导师，善于引导学生，语气需要鼓励型。请以自然语言的方式，简洁易懂地将查询结果表述出来。回答应该:首先确认用户的问题，然后清晰地呈现查询结果，可以给出一些建议信息，字数不超过300字。
        """
        
        response = self.client.chat.completions.create(
            model="glm-4",
            messages=[{"role": "user", "content": prompt}],
            temperature=0.7
        )
        
        return response.choices[0].message.content
    
    def query_with_llm(self, user_question, query_type, query_param):
        """封装关联规则查询和LLM调用的统一接口"""
        result_str = ""
        # 处理多技能查询
        if any(connector in query_param for connector in ['和', '与', '及', ',', '、']):
            if query_type == 'skill_association':
                result = self.get_associated_skills_multiple(query_param)
                if not result:
                    result_str = f"没有找到与'{query_param}'相关的技术推荐。"
                else:
                    result_str = f"根据关联规则分析，同时掌握{query_param}相关的技术有: {', '.join(result)}"
            
            elif query_type == 'skill_positions':
                result = self.get_positions_by_skills(query_param)
                if not result:
                    result_str = f"没有找到同时需要{query_param}技能的岗位。"
                else:
                    position_info = [f"{position} ({percentage})" for position, percentage in result]
                    result_str = f"同时掌握{query_param}技能可以应聘以下岗位（百分占比）: {', '.join(position_info)}"
            
            else:
                return self._query_single(user_question, query_type, query_param)
        else:
            return self._query_single(user_question, query_type, query_param)
        
        print(f"查询结果: {result_str}")  # 打印查询结果

        # 使用LLM生成自然语言回答
        prompt = f"""
        用户问题: {user_question}
        
        查询结果: {result_str}
        
        你是一个帮助学生规划职业道路的导师，善于引导学生，语气需要鼓励型。请以自然语言的方式，简洁易懂地将查询结果表述出来。回答应该:首先确认用户的问题，然后清晰地呈现查询结果，可以给出一些建议信息，字数不超过300字。
        """
        
        response = self.client.chat.completions.create(
            model="glm-4",
            messages=[{"role": "user", "content": prompt}],
            temperature=0.7
        )
        
        return response.choices[0].message.content
    
    def chat_interface(self):
        """交互式聊天界面"""
        print("欢迎使用职业规划助手！我可以帮你解答以下三类问题:")
        print("1. 我比较擅长xxx，请给我推荐一些关联技术")
        print("2. 从事xxx岗位需要学什么？")
        print("3. 我会xxx，什么岗位比较适合我？")
        print("请输入你的问题，或输入'退出'结束对话。\n")
        
        while True:
            try:
                user_input = input("你的问题: ").strip()
                if not user_input:
                    print("请输入有效的问题或输入'退出'结束对话。")
                    continue
                    
                if user_input.lower() in ['退出', 'exit', 'quit']:
                    print("感谢使用，再见！")
                    break
                
                # 识别问题类型
                function_called = ""
                if re.search(r'擅长|会.*(技术|关联)', user_input):
                    # 类型1: 推荐关联技术
                    skill_part = re.sub(r'.*(擅长|会)', '', user_input).split('，')[0].strip()
                    function_called = "query_with_llm (skill_association)"
                    answer = self.query_with_llm(user_input, 'skill_association', skill_part)
                
                elif re.search(r'岗位需要|需要学什么|.*(学什么|学哪些)', user_input):
                    # 类型2: 岗位需要的技术
                    position = re.sub(r'从事|岗位|需要学什么|学什么|学哪些|[？?]', '', user_input).strip()
                    function_called = "query_with_llm (position_skills)"
                    answer = self.query_with_llm(user_input, 'position_skills', position)
                
                elif re.search(r'会.*(岗位|适合)|什么.*适合', user_input):
                    # 类型3: 技术对应的岗位
                    skill_part = re.sub(r'.*会|什么.*', '', user_input).split('，')[0].strip()
                    function_called = "query_with_llm (skill_positions)"
                    answer = self.query_with_llm(user_input, 'skill_positions', skill_part)
                
                else:
                    print("无法识别问题类型，请尝试以下格式提问:")
                    print("1. 我比较擅长Java，请给我推荐一些关联技术")
                    print("2. 算法工程师需要学什么？")
                    print("3. 我会Python，什么岗位比较适合我？")
                    continue
                
                if function_called:
                    print(f"调用的函数: {function_called}")
                # 查询结果已经在 _query_single 或 query_with_llm 中打印
                print("\n助手:", answer)
                # 添加分割线
                print("-" * 50)
                
            except KeyboardInterrupt:
                print("\n感谢使用，再见！")
                break
            except Exception as e:
                print(f"处理问题时出错: {str(e)}")
                continue

# 使用示例
if __name__ == "__main__":
    advisor = CareerAdvisor(api_key="0e333906a9ee486ebcf32b5d89f10b58.JYCfgpGQqYVkvDur")
    advisor.chat_interface()